/*
 * @Author: miteng 973203639@qq.com
 * @Date: 2023-12-21 09:19:21
 * @LastEditors: shiweizhen 787632169@qq.com
 * @LastEditTime: 2025-07-04 17:10:00
 * @Description:
 * Copyright (c) 2024-present HBIS Digital Technology Co.,Ltd. All rights reserved.
 */
/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele: HTMLElement, cls: string): boolean {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele: HTMLElement, cls: string): void {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls;
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele: HTMLElement, cls: string): void {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
    ele.className = ele.className.replace(reg, ' ');
  }
}

export function mix(color1: string, color2: string, weight: number): string {
  weight = Math.max(Math.min(Number(weight), 1), 0);
  const r1 = parseInt(color1.substring(1, 3), 16);
  const g1 = parseInt(color1.substring(3, 5), 16);
  const b1 = parseInt(color1.substring(5, 7), 16);
  const r2 = parseInt(color2.substring(1, 3), 16);
  const g2 = parseInt(color2.substring(3, 5), 16);
  const b2 = parseInt(color2.substring(5, 7), 16);
  const r = Math.round(r1 * (1 - weight) + r2 * weight);
  const g = Math.round(g1 * (1 - weight) + g2 * weight);
  const b = Math.round(b1 * (1 - weight) + b2 * weight);
  const rStr = ('0' + (r || 0).toString(16)).slice(-2);
  const gStr = ('0' + (g || 0).toString(16)).slice(-2);
  const bStr = ('0' + (b || 0).toString(16)).slice(-2);
  return '#' + rStr + gStr + bStr;
}
// 大驼峰法
export function upperCamelCase(str: string): string {
  return str.replace(/(^.)|\_([a-zA-Z])/g, function (a, x1, y1) {
    return (x1 || y1).toLocaleUpperCase();
  });
}

/**
 * 校验表达式是否合法
 * @param expression
 * @returns
 */
export function isValidExpression(expr: string): boolean {
  const tokens: string[] = [];
  let currentToken = '';
  const operatorOrParen = ['+', '-', '*', '/', '(', ')'];

  // 1. 拆分标记（兼容普通变量、F函数、运算符）
  for (const char of expr) {
    if (operatorOrParen.includes(char)) {
      if (currentToken) tokens.push(currentToken);
      tokens.push(char);
      currentToken = '';
    } else {
      currentToken += char;
    }
  }
  if (currentToken) tokens.push(currentToken);

  // 2. 验证标记类型（禁止非法变量）
  for (const token of tokens) {
    if (operatorOrParen.includes(token)) continue; // 跳过运算符/括号
    if (!/^(?:[a-zA-Z]+|F[0-9]+|num)$/.test(token)) {
      return false; // 非法标记（如 aF1、F12F）
    }
  }

  // 3. 状态机验证表达式结构
  let state: 'expectOperand' | 'expectOperator' = 'expectOperand';
  const stack: string[] = [];

  for (const token of tokens) {
    if (state === 'expectOperand') {
      if (token === '(') {
        stack.push(token);
      } else if (operatorOrParen.includes(token) && token !== '(') {
        return false; // 运算符不能出现在操作数位置
      } else {
        state = 'expectOperator'; // 操作数后必须接运算符或 `)`
      }
    } else {
      // expectOperator 状态
      if (token === ')') {
        if (stack.pop() !== '(') return false; // 括号不匹配
      } else if (operatorOrParen.slice(0, 4).includes(token)) {
        state = 'expectOperand'; // 运算符后必须接操作数
      } else {
        return false; // 操作数不能连续出现（如 `a F1`）
      }
    }
  }

  // 4. 最终状态校验
  return state === 'expectOperator' && stack.length === 0;
}

export function isValidFString(input: string): boolean {
  const regex = /^(F[0-9])+$/;
  return regex.test(input);
}
